package cn.miju.ser.common.aspect;

import cn.hutool.core.bean.BeanUtil;
import cn.miju.alipay.properties.AlipayProperties;
import cn.miju.database.constant.DbConstant;
import cn.miju.database.entity.Merchant;
import cn.miju.database.model.AlipayMerchantProperties;
import cn.miju.database.model.UnionPayMerchantProperties;
import cn.miju.ser.framework.constant.SerConstant;
import cn.miju.ser.framework.exception.ApiException;
import cn.miju.ser.framework.handler.MiJuContext;
import cn.miju.ser.framework.handler.MiJuContextHandler;
import cn.miju.unionpay.properties.UnionPayProperties;
import cn.miju.wechatpay.properties.WechatpayProperties;
import com.alibaba.fastjson2.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * <pre>
 * 追加参数到能力层
 * </pre>
 *
 * @author zhuming
 * @version 1.0.0
 * @since 2023-03-14 10:22
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class AppendParamToAbilityAspect {

    private final StringRedisTemplate redisTemplate;

    @SneakyThrows
    @Around("execution(public * cn.miju.*.handler..*.doPlan(..))")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        Object param = args[0];
        MiJuContext miJuContext = MiJuContextHandler.getMiJuContext();
        String merchantInfoKey = SerConstant.Redis.MERCHANT_INFO + miJuContext.getMerchantId();
        if (Boolean.FALSE.equals(redisTemplate.hasKey(merchantInfoKey))) {
            throw new ApiException(String.format("未读取到商户缓存[key：%s]信息！", merchantInfoKey));
        }
        Merchant merchant = JSONObject.parseObject(redisTemplate.opsForValue().get(merchantInfoKey), Merchant.class);
        if (Objects.isNull(merchant)) {
            throw new ApiException(String.format("商户缓存[key：%s]信息读取为空！", merchantInfoKey));
        }
        if (StringUtils.isBlank(merchant.getMerchantProperties())) {
            throw new ApiException("未添加商户配置参数");
        }
        if (DbConstant.MerchantType.ALIPAY.equals(merchant.getMerchantType())) {
            AlipayProperties alipayProperties = BeanUtil.copyProperties(merchant.getAlipayMerchantProperties(), AlipayProperties.class);
            Field alipayPropertiesField = param.getClass().getSuperclass().getDeclaredField("alipayProperties");
            alipayPropertiesField.setAccessible(true);
            alipayPropertiesField.set(param, alipayProperties);
            alipayPropertiesField.setAccessible(false);
        } else if (DbConstant.MerchantType.WECHAT.equals(merchant.getMerchantType())) {
            WechatpayProperties wechatpayProperties = BeanUtil.copyProperties(merchant.getWechatpayMerchantProperties(), WechatpayProperties.class);
            Field wechatpayPropertiesField = param.getClass().getSuperclass().getDeclaredField("wechatpayProperties");
            wechatpayPropertiesField.setAccessible(true);
            wechatpayPropertiesField.set(param, wechatpayProperties);
            wechatpayPropertiesField.setAccessible(false);
        } else if (DbConstant.MerchantType.UNIONPAY.equals(merchant.getMerchantType())) {
            UnionPayMerchantProperties unionPayMerchantProperties = BeanUtil.copyProperties(merchant.getUnionPayMerchantProperties(), UnionPayMerchantProperties.class);
            UnionPayProperties unionPayProperties = BeanUtil.copyProperties(unionPayMerchantProperties, UnionPayProperties.class);
            Field unionPayPropertiesField = param.getClass().getSuperclass().getDeclaredField("unionPayProperties");
            unionPayPropertiesField.setAccessible(true);
            unionPayPropertiesField.set(param, unionPayProperties);
            unionPayPropertiesField.setAccessible(false);
        }
        return joinPoint.proceed();
    }
}
